// clientleader
package main

import (
	"container/list"
	"fmt"
	"log"
	"sort"
	"strings"
	"time"

	"golang.org/x/net/context"
)

//leader处理的逻辑模块
type ClientLeader struct {
	etcdAndZkMaster *EtcdAndZkMaster
	dataRange       map[string]map[string]*list.List //归类数据 //map[客户端id]*map[应用名]*list.List
	dataEmpty       map[string]*list.List            //未进行处理的数据

}

func NewClientLeader(eaz *EtcdAndZkMaster) *ClientLeader {
	return &ClientLeader{etcdAndZkMaster: eaz, dataRange: make(map[string]map[string]*list.List), dataEmpty: make(map[string]*list.List)}
}

//领导初始
func (cl *ClientLeader) InitLeader() {
	cl.InitPodData()
	cl.CheckPodTypeData()
}

//心跳模块，
func (cl *ClientLeader) HeartLeaderModule() {
	for {
		if mainStatic.CHECK_RESTART == true {
			break
		}
		cl.CheckClientDownData()
		cl.DispatcherData()

		time.Sleep(10)

	}
}

//收集POD的数据
func (cl *ClientLeader) InitPodData() {
	etcdMater := cl.etcdAndZkMaster.etcdMaster
	//获取Pod的路径
	_val, err := etcdMater.KeysAPI.Get(context.Background(), ETCD_WATCH_PATH, nil)
	if err != nil {
		log.Fatal("Error: InitPodData:", err)
		fmt.Print("=========(8)=========================")
		mainStatic.CHECK_RESTART = true
		return
	}
	//fmt.Println(_val.Node.Nodes[0].Value)
	//var nodeValue map[string]interface{}
	//根据namespace获取pod信息
	for j := 0; j < _val.Node.Nodes.Len(); j++ {
		_second, err := etcdMater.KeysAPI.Get(context.Background(), _val.Node.Nodes[j].Key, nil)
		if err != nil {
			log.Fatal("Error: InitPodData:", err)
			fmt.Print("=========(8)=========================")
			mainStatic.CHECK_RESTART = true
			return
		}
		for i := 4; i < _second.Node.Nodes.Len(); i++ {
			pwf := etcdMater.GetPodWokerInfo(_second.Node.Nodes[i].Value)
			if pwf == nil {
				continue
			}
			//cl.podKey[_val.Node.Nodes[i].Key] = pwf.AppName + ":" + pwf.IP + ":" + pwf.Port
			//fmt.Println("##################===InitPodData===:" + pwf.AppName)
			member := &Member{AppName: pwf.AppName, IP: pwf.IP, Port: pwf.Port, HostIP: pwf.HostIP, Key: _second.Node.Nodes[i].Key}
			cl.AddDataEmptyQueue(member)
		}
	}

}

//增加分配队列
func (cl *ClientLeader) AddDataEmptyQueue(member *Member) {
	//cl.podKey[member.Key] = member.AppName + ":" + member.IP + ":" + member.Port
	mem := cl.SearchDataEmptyMember(member)
	if mem != nil {
		return
	}
	_data := cl.dataEmpty[member.AppName]
	if _data == nil {
		_data = list.New()
		cl.dataEmpty[member.AppName] = _data
	}
	_data.PushBack(member)
}

//检查Pod分组的信息
func (cl *ClientLeader) CheckPodTypeData() {

	//fmt.Println("=====CheckPodTypeData======")
	zkMaster := cl.etcdAndZkMaster.zkMaster
	etcdMater := cl.etcdAndZkMaster.etcdMaster

	api := etcdMater.KeysAPI

	zkcli, _, err := zkMaster.zkConnect.Children(mainStatic.ZK_HV_WATCH_PATH + "/client")

	if err != nil {
		fmt.Print("=========(7)=========================")
		mainStatic.CHECK_RESTART = true
		return
	}
	for _, clientId := range zkcli {
		resp, err := api.Get(context.Background(), mainStatic.ETCD_HV_WATCH_PATH+"/"+clientId+"/", nil)
		if err != nil {
			fmt.Println("######################")
			fmt.Println(err)
			continue

		}
		for _, node := range resp.Node.Nodes {
			member := etcdMater.GetPodModelMember(node.Key, node.Value)
			mem := cl.SearchDataEmptyMember(member)
			if mem == nil {
				continue
			}

			clientdata := cl.dataRange[clientId]
			if clientdata == nil {
				//tmpmap := make(map[string]*list.List)
				//clientdata = &tmpmap
				clientdata = make(map[string]*list.List)
				cl.dataRange[clientId] = clientdata
			}
			//已经注册到ZK
			//if zkMaster.ExistsZkPath(member) == true {
			appdata := clientdata[mem.AppName]
			if appdata == nil {
				appdata = list.New()
				clientdata[mem.AppName] = appdata
			}

			if cl.ExistsAppData(appdata, mem) == false {
				mem.ClientId = clientId
				appdata.PushBack(mem)
			}
			cl.DeleteDataEmpty(mem)
			//}

		}

	}

}

//检查客户端下线的数据
func (cl *ClientLeader) CheckClientDownData() {

	zkMaster := cl.etcdAndZkMaster.zkMaster
	etcdMater := cl.etcdAndZkMaster.etcdMaster

	etcddata := make(map[string]*list.List)
	zkdata := make(map[string]*list.List)

	//etcd里分组处理
	api := etcdMater.KeysAPI
	resp, err := api.Get(context.Background(), mainStatic.ETCD_HV_WATCH_PATH+"/", nil)
	if err != nil {
		return
	}

	if resp == nil || resp.Node == nil || resp.Node.Nodes == nil {
		return
	}

	for _, node := range resp.Node.Nodes {
		cp := strings.Split(node.Key, "/")
		clid := cp[len(cp)-1]
		etcddata[clid] = list.New()
	}
	//zk里的客户端信息
	zkcli, _, err := zkMaster.zkConnect.Children(mainStatic.ZK_HV_WATCH_PATH + "/client")
	if err != nil {
		fmt.Print("=========(3)=========================")
		mainStatic.CHECK_RESTART = true
		return
	}

	for _, clientId := range zkcli {
		zkdata[clientId] = list.New()

		if cl.dataRange[clientId] == nil {
			clientdata := make(map[string]*list.List)
			cl.dataRange[clientId] = clientdata
		}

	}
	//对比处理
	for clid, _ := range etcddata {
		if zkdata[clid] != nil {
			continue
		}
		clientdata := cl.dataRange[clid]
		if clientdata == nil {
			//删除
			etcdMater.DeleteEtcdPath(mainStatic.ETCD_HV_WATCH_PATH + "/" + clid)
			continue
		}
		//设置重新分配
		for appname, data := range clientdata {
			for e := data.Front(); e != nil; e = data.Front() {
				_member := e.Value.(*Member)
				_member.ClientId = ""
				cl.dataEmpty[appname].PushBack(_member)
				//存在
				//if zkMaster.ExistsZkPath(_member) == true {
				//}
				data.Remove(e)
			}

			delete(clientdata, appname)
		}
		delete(cl.dataRange, clid)
	}
}

//调度数据给客户端注册
func (cl *ClientLeader) DispatcherData() {

	for _, data := range cl.dataEmpty {
		for e := data.Front(); e != nil; {
			//_member := e.Value.(*Member)
			if cl.AssignedDataClient(e) == false {
				e = e.Next()
			} else {
				e = data.Front()
			}

		}
	}

}

//数据分配到客户端
func (cl *ClientLeader) AssignedDataClient(e *list.Element) bool {
	_member := e.Value.(*Member)
	//	fmt.Println("*****AssignedDataClient******appName:" + _member.AppName + "*****IP:" + _member.IP + "*****port:" + _member.Port)
	if cl.SwapClientSort(_member) == false {
		return false
	}
	//fmt.Println("*****AssignedDataClient******appName:" + _member.AppName + "*****IP:" + _member.IP + "*****port:" + _member.Port)

	clientdata := cl.dataRange[_member.ClientId]
	if clientdata == nil {
		_member.ClientId = ""
		return false
	}

	appdata := clientdata[_member.AppName]
	if appdata == nil {
		appdata = list.New()
		clientdata[_member.AppName] = appdata
	}

	if cl.dataEmpty[_member.AppName] != nil {
		cl.dataEmpty[_member.AppName].Remove(e)
	}
	//已经存在
	if cl.ExistsAppData(appdata, _member) == true {
		return true
	}

	appdata.PushBack(_member)
	//=====================写ECTD==============
	etcdMater := cl.etcdAndZkMaster.etcdMaster
	etcdMater.AddEtcdHvInfo(_member)

	return true

}

//得到某应用在各客户端注册的排序
func (cl *ClientLeader) SwapClientSort(_member *Member) bool {
	pList := cl.GetAllClientSort()

	clientAppSort := make([]*ClientSort, len(cl.dataRange))
	//fmt.Println(len(cl.dataRange))

	index := 0
	for clientId, clientdata := range cl.dataRange {
		data := clientdata[_member.AppName]
		if data == nil {
			clientAppSort[index] = &ClientSort{clientId, 0}
			index += 1
			continue
		}
		clientAppSort[index] = &ClientSort{clientId, data.Len() * cl.GetClientSortNum(pList, clientId)}
		index += 1
	}

	if index == 0 {
		//fmt.Println("=========SwapClientSort===============")
		return false
	}

	slist := ClientSortList(clientAppSort)
	sort.Sort(slist)
	_member.ClientId = slist[0].clientId

	return true

}

//得到某客户端注册的总数
func (cl *ClientLeader) GetClientSortNum(pList ClientSortList, clientId string) int {
	for _, clientSort := range pList {
		if clientSort.clientId == clientId {
			return clientSort.podNum
		}
	}
	return 0
}

//得到注册到客户端从小到大的数组
func (cl *ClientLeader) GetAllClientSort() ClientSortList {
	clientSort := make([]*ClientSort, len(cl.dataRange))

	index := 0
	for clientid, clientdata := range cl.dataRange {
		//clientSort[index] = &ClientSort{clientid}
		sum := 0
		for _, data := range clientdata {
			sum += data.Len()

		}
		clientSort[index] = &ClientSort{clientid, sum}
		index += 1
	}
	pList := ClientSortList(clientSort)
	sort.Sort(pList)
	return pList
}

func (cl *ClientLeader) SearchDataEmptyMember(member *Member) *Member {
	_data := cl.dataEmpty[member.AppName]
	if _data == nil {
		return nil
	}
	for e := _data.Front(); e != nil; e = e.Next() {

		_member := e.Value.(*Member)

		if _member.AppName == member.AppName && _member.IP == member.IP && _member.Port == member.Port {
			return _member
		}
	}
	return nil
}

func (cl *ClientLeader) SearchClientData(key string) *Member {
	//到每一个分组里找相关记录
	for _, clientdata := range cl.dataRange {
		for _, data := range clientdata {
			for e := data.Front(); e != nil; e = e.Next() {
				_member := e.Value.(*Member)
				if _member.Key == key {
					return _member
				}
			}
		}
	}

	return nil
}

//删除客户端的记录
func (cl *ClientLeader) DeleteClientData(member *Member) bool {
	etcdMater := cl.etcdAndZkMaster.etcdMaster
	if cl.DeleteDataEmpty(member) == true {
		return true
	}
	//到每一个分组里找相关记录
	for clientId, clientdata := range cl.dataRange {
		//data := clientdata[_member.AppName]
		for _, data := range clientdata {

			if cl.ExistsAppData(data, member) == false {
				continue
			}
			//找到记录
			path := mainStatic.ETCD_HV_WATCH_PATH + "/" + clientId + "/" + member.AppName + ":" + member.IP + ":" + member.Port
			etcdMater.DeleteEtcdPath(path)
			cl.RemoveClientElement(data, member)
			return true
		}

	}

	return false
}

//删除
func (cl *ClientLeader) RemoveClientElement(data *list.List, member *Member) bool {

	for e := data.Front(); e != nil; e = e.Next() {
		_member := e.Value.(*Member)
		if _member.AppName == member.AppName && _member.IP == member.IP && _member.Port == member.Port {
			data.Remove(e)
			return true
		}
	}

	return false

}

//删除等待注册的数据
func (cl *ClientLeader) DeleteDataEmpty(member *Member) bool {
	data := cl.dataEmpty[member.AppName]
	if data == nil {
		return false
	}
	for e := data.Front(); e != nil; e = e.Next() {
		//fmt.Println("removing", e.Value)
		// l.Remove(e)
		_member := e.Value.(*Member)
		//查到删除
		if _member.AppName == member.AppName && _member.IP == member.IP && _member.Port == member.Port {
			data.Remove(e)
			return true
		}
	}

	return false

}

//是否APP已存在
func (cl *ClientLeader) ExistsAppData(data *list.List, member *Member) bool {
	for e := data.Front(); e != nil; e = e.Next() {
		//fmt.Println("removing", e.Value)
		// l.Remove(e)
		_member := e.Value.(*Member)
		if _member.AppName == member.AppName && _member.IP == member.IP && _member.Port == member.Port {
			return true
		}
	}

	return false
}
